#lang racket


(provide list-rand
         butlast
         last
         partition-index
         reduce
         reducer
         zip)


(define (list-rand lst)
  (list-ref lst (random (length lst))))

(define (butlast lst)
  (if (empty? (rest lst))
      (list)
      (cons (first lst) (butlast (rest lst)))))

(define (last lst)
  (if (empty? (rest lst))
      lst
      (last (rest lst))))

(define (partition-index pred lst)
  (define (partition-index-aux i aux1 aux2 lst)
    (if (null? lst)
        (values aux1 aux2)
        (let ((e (first lst)))
          (if (pred i e)
              (partition-index-aux (add1 i) (cons e aux1) aux2 (rest lst))
              (partition-index-aux (add1 i) aux1 (cons e aux2) (rest lst))))))
  (partition-index-aux 0 (list) (list) (reverse lst)))

(define (reduce proc lst)
  (if (empty? lst)
      (list)
      (foldl proc (first lst) (rest lst))))

(define (reducer proc lst)
  (if (empty? lst)
      (list)
      (foldr proc (first (last lst)) (butlast lst))))

(define (zip lst1 lst2)
  (define (zip-aux lst1 lst2 lst)
    (if (or (null? lst1) (null? lst2))
        (reverse lst)
        (zip-aux (rest lst1) (rest lst2) (cons (list (first lst1) (first lst2)) lst))))
  (zip-aux lst1 lst2 (list)))